using System;
using System.Threading;
using ch.ethz.ssh2.util;
namespace ch.ethz.ssh2.channel
{
	
	/// <summary> A StreamForwarder forwards data between two given streams. 
	/// If two StreamForwarder threads are used (one for each direction)
	/// then one can be configured to shutdown the underlying channel/socket
	/// if both threads have finished forwarding (EOF).
	/// 
	/// </summary>
	/// <author>  Christian Plattner
	/// </author>
	/// <version>  2.50, 03/15/10
	/// </version>
	public class StreamForwarder
	{
		internal System.IO.Stream output;
		internal System.IO.Stream input;
		internal byte[] buffer;
		internal Channel channel;
		internal Thread sibling;
		internal System.Net.Sockets.TcpClient client;
		internal System.String mode;
		
		internal StreamForwarder(Channel channel, Thread sibling, System.Net.Sockets.TcpClient client, System.IO.Stream input, System.IO.Stream output, System.String mode)
		{
            buffer = new byte[Channel.CHANNEL_BUFFER_SIZE];
			this.input = input;
			this.output = output;
			this.mode = mode;
			this.channel = channel;
			this.sibling = sibling;
			this.client = client;
		}
		
		public void  Run()
		{
			try
			{
				while (true)
				{
					int len = (input is ch.ethz.ssh2.StreamGobbler || input is ch.ethz.ssh2.channel.ChannelInputStream)?(int) Utility.InvokeMethodAsVirtual(input, "read", new System.Object[]{buffer}):Utility.ReadInput(input, buffer, 0, buffer.Length);
					if (len <= 0)
						break;
					output.Write(buffer, 0, len);
					output.Flush();
				}
			}
			catch (System.IO.IOException ignore)
			{
				try
				{
					//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
					channel.cm.closeChannel(channel, "Closed due to exception in StreamForwarder (" + mode + "): " + ignore.Message, true);
				}
				catch (System.IO.IOException e)
				{
				}
			}
			finally
			{
				try
				{
					output.Close();
				}
				catch (System.IO.IOException e1)
				{
				}
				try
				{
					input.Close();
				}
				catch (System.IO.IOException e2)
				{
				}
				
				if (sibling != null)
				{
					while (sibling.IsAlive)
					{
						try
						{
							sibling.Join();
						}
						catch (System.Threading.ThreadInterruptedException e)
						{
							Thread.CurrentThread.Interrupt();
						}
					}
					
					try
					{
						channel.cm.closeChannel(channel, "StreamForwarder (" + mode + ") is cleaning up the connection", true);
					}
					catch (System.IO.IOException e3)
					{
					}
					
					try
					{
						if (client != null)
							client.Close();
					}
					catch (System.IO.IOException e1)
					{
					}
				}
			}
		}
	}
}